package com.stripe.stripe_terminal

import android.Manifest
import android.app.Activity
import android.content.Context.LOCATION_SERVICE
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.location.LocationManager
import android.os.Build
import android.os.Bundle
import androidx.annotation.NonNull
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.google.gson.Gson
import com.stripe.stripeterminal.Terminal
import com.stripe.stripeterminal.TerminalApplicationDelegate
import com.stripe.stripeterminal.external.callable.*
import com.stripe.stripeterminal.external.models.*
import com.stripe.stripeterminal.log.LogLevel
import io.flutter.app.FlutterActivityEvents
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.PluginRegistry
import org.json.JSONObject
import java.util.*
import kotlin.collections.HashMap

/** StripeTerminalPlugin */
class StripeTerminalPlugin : FlutterPlugin, MethodCallHandler,
    PluginRegistry.RequestPermissionsResultListener, ActivityAware, FlutterActivityEvents {

    private lateinit var channel: MethodChannel
    private var currentActivity: Activity? = null
    private val REQUEST_CODE_LOCATION = 1012
    private lateinit var tokenProvider: StripeTokenProvider
    private var cancelableDiscover: Cancelable? = null
    private var cancelableReconnection: Cancelable? = null
    private var activeReaders: List<Reader> = arrayListOf()
    private var simulated = false
    private val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        arrayOf(
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.BLUETOOTH_SCAN,
            Manifest.permission.BLUETOOTH_CONNECT,
        )
    } else {
        arrayOf(
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.BLUETOOTH,
            Manifest.permission.BLUETOOTH_ADMIN,
        )
    }

    private var cancelablePayment: Cancelable? = null
    private var currentPaymentIntent: PaymentIntent? = null
    private var currentOrderId: String? = null
    private var cancelableInstallation: Cancelable? = null

    // Change this to other level soon
    private val logLevel = LogLevel.VERBOSE

    // Create your listener object. Override any methods that you want to be notified about
    val listener = object : TerminalListener {
        override fun onUnexpectedReaderDisconnect(reader: Reader) {
            // TODO: Trigger the user about the issue.
            val rawReader = reader.rawJson()
            currentActivity?.runOnUiThread {
                channel.invokeMethod("onUnexpectedReaderDisconnect", rawReader)
                generateLog("onUnexpectedReaderDisconnect", Gson().toJson(rawReader))
            }
        }

        override fun onConnectionStatusChange(status: ConnectionStatus) {
            super.onConnectionStatusChange(status)
            currentActivity?.runOnUiThread {
                channel.invokeMethod("onConnectionStatusChange", handleConnectionStatus(status))
                generateLog("onConnectionStatusChange", status.toString())
            }
        }

        override fun onPaymentStatusChange(status: PaymentStatus) {
            super.onPaymentStatusChange(status)
            currentActivity?.runOnUiThread {
                channel.invokeMethod("onPaymentStatusChange", handlePaymentStatus(status))
                generateLog("onPaymentStatusChange", status.toString())
            }
        }
    }

    val reconnectionListener = object : ReaderReconnectionListener {
        override fun onReaderReconnectFailed(reader: Reader) {
            cancelableReconnection = null
            val rawReader = reader.rawJson()
            currentActivity?.runOnUiThread {
                channel.invokeMethod("onReaderReconnectFailed", rawReader)
                generateLog("onReaderReconnectFailed", Gson().toJson(rawReader))
            }
        }

        override fun onReaderReconnectStarted(reader: Reader, cancelReconnect: Cancelable) {
            cancelableReconnection = cancelReconnect;
            currentActivity?.runOnUiThread {
                channel.invokeMethod("onReaderReconnectStarted", null)
                generateLog("onReaderReconnectStarted", "onReaderReconnectStarted")
            }
        }

        override fun onReaderReconnectSucceeded(reader: Reader) {
            currentActivity?.runOnUiThread {
                channel.invokeMethod("onReaderReconnectSucceeded", null)
                generateLog("onReaderReconnectSucceeded", "onReaderReconnectSucceeded")
            }
        }
    }


    override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
        channel = MethodChannel(flutterPluginBinding.binaryMessenger, "stripe_terminal")
        channel.setMethodCallHandler(this)
    }


    fun _startStripe() {
        // Pass in the current application context, your desired logging level, your token provider, and the listener you created
        if (!Terminal.isInitialized()) {
            try {
                Terminal.initTerminal(
                    currentActivity!!.applicationContext,
                    logLevel,
                    tokenProvider,
                    listener
                )
                result?.success(true)
            } catch (e: Exception) {
                throw e
            }
        }

    }

    private fun generateLog(code: String, message: String) {
        val log: HashMap<String, String> = HashMap()
        log["code"] = code
        log["message"] = message
        channel.invokeMethod("onNativeLog", log)
    }

    override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
        when (call.method) {
            "init" -> {
                if (_isLocServiceEnable()) {
                    if (_isPermissionAllowed(result)) {
                        try {
                            _startStripe()
                        } catch (e: Exception) {
                            channel.invokeMethod("callbackStripeInitError", e.message.toString())
                        }
                    }
                } else {
                    channel.invokeMethod("callbackStripeInitError", "Location service has been disabled.")
                    return result.success(false)
                }
            }
            "clearReaderDisplay" -> {
                Terminal.getInstance().clearReaderDisplay(object :Callback{
                    override fun onFailure(e: TerminalException) {
                        return result.error(
                            "stripeTerminal#unableToClearDisplay",
                            e.errorMessage,
                            e.stackTraceToString()
                        )                    }

                    override fun onSuccess() {
                        result.success(true)
                    }
                })
            }
            "setReaderDisplay" -> {
                val arguments = call.arguments as HashMap<*, *>
                val rawReaderDisplay = arguments["readerDisplay"] as HashMap<*, *>

                val readerDisplay = ReaderDisplay.fromJson(Gson().toJson(rawReaderDisplay))
                    ?: return result.error(
                        "stripeTerminal#unableToDisplay",
                        "Invalid `readerDisplay` value provided",
                        null
                    )
                val cart = Cart.Builder(
                    currency = readerDisplay.cart.currency,
                    tax = readerDisplay.cart.tax,
                    total = readerDisplay.cart.total
                )
                cart.lineItems = readerDisplay.cart.lineItems.map {
                    CartLineItem.Builder(
                        description = it.description,
                        quantity = it.quantity,
                        amount = it.amount
                    ).build()
                }

                Terminal.getInstance().setReaderDisplay(cart.build(), object : Callback {
                    override fun onSuccess() {
                        result.success(true);
                    }

                    override fun onFailure(e: TerminalException) {
                        return result.error(
                            "stripeTerminal#unableToDisplay",
                            e.errorMessage,
                            e.stackTraceToString()
                        )
                    }
                })
            }
            "discoverReaders#start" -> {
                val arguments = call.arguments as HashMap<*, *>
                val discoverConfig = arguments["config"] as HashMap<*, *>

                generateLog(
                    "discoverReaders",
                    "Started the discover process. Simulated mode: $simulated"
                )

                val config = DiscoveryConfiguration.BluetoothDiscoveryConfiguration(
                    isSimulated = discoverConfig["simulated"] as Boolean,
                    timeout = discoverConfig["timeout"] as Int,
                )

                if (ActivityCompat.checkSelfPermission(
                        currentActivity!!.applicationContext,
                        Manifest.permission.ACCESS_FINE_LOCATION
                    ) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
                        currentActivity!!.applicationContext,
                        Manifest.permission.ACCESS_COARSE_LOCATION
                    ) != PackageManager.PERMISSION_GRANTED
                ) {
                    _isPermissionAllowed(result)
                    return
                }
                cancelableDiscover =
                    Terminal.getInstance().discoverReaders(config, object : DiscoveryListener {

                        override fun onUpdateDiscoveredReaders(readers: List<Reader>) {
                            activeReaders = readers
                            val rawReaders = readers.map {
                                it.rawJson()
                            }
                            currentActivity?.runOnUiThread {
                                channel.invokeMethod("onReadersFound", rawReaders)
                                generateLog("onUpdateDiscoveredReaders", Gson().toJson(rawReaders))
                            }
                        }


                    }, object : Callback {
                        override fun onFailure(e: TerminalException) {
                            result.error(
                                "stripeTerminal#unabelToDiscover",
                                e.message,
                                e.stackTraceToString()
                            )
                        }

                        override fun onSuccess() {
                            result.success(true)
                        }
                    })
            }
            "discoverReaders#stop" -> {
                if (cancelableDiscover == null) {
                    result.error(
                        "stripeTerminal#unabelToCancelDiscover",
                        "There is no discover action running to stop.",
                        null
                    )
                } else {
                    cancelableDiscover?.cancel(object : Callback {
                        override fun onFailure(e: TerminalException) {
                            result.error(
                                "stripeTerminal#unabelToCancelDiscover",
                                "Unable to stop the discover action because ${e.errorMessage}",
                                e.stackTraceToString()
                            )
                        }

                        override fun onSuccess() {
                            result.success(true)
                        }
                    })
                    cancelableDiscover = null

                }
            }
            "reconnect#stop" -> {
                if (cancelableReconnection == null) {
                    result.error(
                            "stripeTerminal#unabelToCancelReconnect",
                            "There is no reconnection action running to stop.",
                            null
                    )
                } else {
                    cancelableReconnection?.cancel(object : Callback {
                        override fun onFailure(e: TerminalException) {
                            result.error(
                                    "stripeTerminal#unabelToCancelReconnect",
                                    "Unable to stop the reconnection action because ${e.errorMessage}",
                                    e.stackTraceToString()
                            )
                        }

                        override fun onSuccess() {
                            result.success(true)
                        }
                    })
                    cancelableReconnection = null

                }
            }
            "fetchConnectedReader" -> {
                result.success(Terminal.getInstance().connectedReader?.rawJson())
            }
            "connectionStatus" -> {
                result.success(handleConnectionStatus(Terminal.getInstance().connectionStatus))
            }
            "connectToInternetReader" -> {
                when (Terminal.getInstance().connectionStatus) {
                    ConnectionStatus.NOT_CONNECTED -> {
                        val arguments = call.arguments as HashMap<*, *>
                        val readerSerialNumber = arguments["readerSerialNumber"] as String
                        val failIfInUse = arguments["failIfInUse"] as Boolean

                        generateLog(
                            "connectToInternetReader",
                            "Started connecting to $readerSerialNumber"
                        )

                        val reader = activeReaders.firstOrNull {
                            it.serialNumber == readerSerialNumber
                        }

                        if (reader == null) {
                            result.error(
                                "stripeTerminal#readerNotFound",
                                "Reader with provided serial number no longer exists",
                                null
                            )
                            return
                        }


                        val connectionConfig =
                            ConnectionConfiguration.InternetConnectionConfiguration(
                                failIfInUse = failIfInUse
                            )
                        Terminal.getInstance().connectInternetReader(
                            reader,
                            connectionConfig,
                            object : ReaderCallback {
                                override fun onFailure(e: TerminalException) {
                                    result.error(
                                        "stripeTerminal#unableToConnect",
                                        e.errorMessage,
                                        e.stackTraceToString()
                                    )
                                }

                                override fun onSuccess(reader: Reader) {
                                    result.success(true)
                                }

                            })
                    }
                    ConnectionStatus.CONNECTING -> {
                        result.error(
                            "stripeTerminal#deviceConnecting",
                            "A new connection is being established with a device thus you cannot request a new connection at the moment.",
                            null
                        )
                    }
                    ConnectionStatus.CONNECTED -> {
                        result.error(
                            "stripeTerminal#deviceAlreadyConnected",
                            "A device with serial number ${Terminal.getInstance().connectedReader!!.serialNumber} is already connected",
                            null
                        )
                    }
                }
            }
            "connectBluetoothReader" -> {
                when (Terminal.getInstance().connectionStatus) {
                    ConnectionStatus.NOT_CONNECTED -> {
                        val arguments = call.arguments as HashMap<*, *>
                        val readerSerialNumber = arguments["readerSerialNumber"] as String
                        val autoReconnectOnUnexpectedDisconnect = arguments["autoReconnectOnUnexpectedDisconnect"] as Boolean

                        generateLog(
                            "connectBluetoothReader",
                            "Started connecting to $readerSerialNumber"
                        )

                        val reader = activeReaders.firstOrNull {
                            it.serialNumber == readerSerialNumber
                        }

                        if (reader == null) {
                            result.error(
                                "stripeTerminal#readerNotFound",
                                "Reader with provided serial number no longer exists",
                                null
                            )
                            return
                        }


                        val locationId: String? = (arguments["locationId"]
                            ?: reader.location?.id) as String?

                        generateLog("connectBluetoothReader", "Location Id $locationId")

                        if (locationId == null) {
                            result.error(
                                "stripeTerminal#locationNotProvided",
                                "Either you have to provide the location id or device should be attached to a location",
                                null
                            )
                            return
                        }
                        val connectionConfig =
                            ConnectionConfiguration.BluetoothConnectionConfiguration(
                                locationId,
                                autoReconnectOnUnexpectedDisconnect,
                                reconnectionListener
                            )
                        Terminal.getInstance().connectBluetoothReader(
                            reader,
                            connectionConfig,
                            object : ReaderListener {
                                override fun onReportAvailableUpdate(update: ReaderSoftwareUpdate) {
                                    super.onReportAvailableUpdate(update)
                                    /// 准备参数
                                    val param: HashMap<String, Any> = HashMap()
                                    param["versionString"] = update.version
                                    param["timeEstimate"] = update.timeEstimate.description
                                    param["requiredAt"] = update.requiredAt.time

                                    currentActivity?.runOnUiThread {
                                        channel.invokeMethod("onReportAvailableUpdate", param)
                                        generateLog(
                                            "onReportAvailableUpdate",
                                            "onReportAvailableUpdate ${update.version}"
                                        )
                                    }
                                }

                                override fun onStartInstallingUpdate(
                                    update: ReaderSoftwareUpdate,
                                    cancelable: Cancelable?
                                ) {
                                    super.onStartInstallingUpdate(update, cancelable)
                                    cancelableInstallation = cancelable
                                    currentActivity?.runOnUiThread {
                                        channel.invokeMethod("onStartInstallingUpdate", update.version)
                                        generateLog(
                                            "onStartInstallingUpdate",
                                            "onStartInstallingUpdate ${update.version}"
                                        )
                                    }
                                }

                                override fun onReportReaderSoftwareUpdateProgress(progress: Float) {
                                    super.onReportReaderSoftwareUpdateProgress(progress)
                                    currentActivity?.runOnUiThread {
                                        channel.invokeMethod("onReportReaderSoftwareUpdateProgress", progress)
                                        generateLog(
                                            "onReportReaderSoftwareUpdateProgress",
                                            "onReportReaderSoftwareUpdateProgress $progress"
                                        )
                                    }
                                }

                                override fun onFinishInstallingUpdate(
                                    update: ReaderSoftwareUpdate?,
                                    e: TerminalException?
                                ) {
                                    super.onFinishInstallingUpdate(update, e)
                                    if (update != null) {
                                        var result = "Install Success"
                                        if (e != null) {
                                            result = e.errorMessage
                                        }

                                        val param: HashMap<String, Any> = HashMap()
                                        param["versionString"] = update.version
                                        param["success"] = (e == null)
                                        param["result"] = result

                                        currentActivity?.runOnUiThread {
                                            channel.invokeMethod("onFinishInstallingUpdate", param)
                                            generateLog(
                                                "onFinishInstallingUpdate",
                                                "onFinishInstallingUpdate $result"
                                            )
                                        }
                                    }
                                }

                                override fun onRequestReaderDisplayMessage(message: ReaderDisplayMessage) {
                                    super.onRequestReaderDisplayMessage(message)
                                    currentActivity?.runOnUiThread {
                                        channel.invokeMethod("onRequestReaderDisplayMessage", handlerReaderMessage(message))
                                        generateLog(
                                            "onRequestReaderDisplayMessage",
                                            "onRequestReaderDisplayMessage $message"
                                        )
                                    }
                                }
                                override fun onReportReaderEvent(event: ReaderEvent) {
                                    super.onReportReaderEvent(event)
                                    currentActivity?.runOnUiThread {
                                        generateLog(
                                            "onReportReaderEvent",
                                            "readerEvent ${event}"
                                        )
                                    }
                                }
                            },
                            object : ReaderCallback {
                                override fun onFailure(e: TerminalException) {
                                    result.error(
                                        "stripeTerminal#unableToConnect",
                                        e.errorMessage,
                                        e.stackTraceToString()
                                    )
                                }

                                override fun onSuccess(reader: Reader) {
                                    result.success(true)
                                }

                            })
                    }
                    ConnectionStatus.CONNECTING -> {
                        result.error(
                            "stripeTerminal#deviceConnecting",
                            "A new connection is being established with a device thus you cannot request a new connection at the moment.",
                            null
                        )
                    }
                    ConnectionStatus.CONNECTED -> {
                        result.error(
                            "stripeTerminal#deviceAlreadyConnected",
                            "A device with serial number ${Terminal.getInstance().connectedReader!!.serialNumber} is already connected",
                            null
                        )
                    }
                }
            }
            "connectUSBReader" -> {
                println("start to connect usb reader")
                when (Terminal.getInstance().connectionStatus) {
                    ConnectionStatus.NOT_CONNECTED -> {
                        val arguments = call.arguments as HashMap<*, *>
                        val readerSerialNumber = arguments["readerSerialNumber"] as String
                        val autoReconnectOnUnexpectedDisconnect = arguments["autoReconnectOnUnexpectedDisconnect"] as Boolean

                        generateLog(
                                "connectUSBReader",
                                "Started connecting to $readerSerialNumber"
                        )

                        val reader = activeReaders.firstOrNull {
                            it.serialNumber == readerSerialNumber
                        }

                        if (reader == null) {
                            result.error(
                                    "stripeTerminal#readerNotFound",
                                    "Reader with provided serial number no longer exists",
                                    null
                            )
                            return
                        }


                        val locationId: String? = (arguments["locationId"]
                                ?: reader.location?.id) as String?

                        generateLog("connectUSBReader", "Location Id $locationId")

                        if (locationId == null) {
                            result.error(
                                    "stripeTerminal#locationNotProvided",
                                    "Either you have to provide the location id or device should be attached to a location",
                                    null
                            )
                            return
                        }
                        val connectionConfig =
                                ConnectionConfiguration.UsbConnectionConfiguration(
                                        locationId,
                                        autoReconnectOnUnexpectedDisconnect,
                                        reconnectionListener
                                )
                        Terminal.getInstance().connectUsbReader(
                                reader,
                                connectionConfig,
                                object : ReaderListener {
                                    override fun onReportAvailableUpdate(update: ReaderSoftwareUpdate) {
                                        super.onReportAvailableUpdate(update)
                                        /// 准备参数
                                        val param: HashMap<String, Any> = HashMap()
                                        param["versionString"] = update.version
                                        param["timeEstimate"] = update.timeEstimate.description
                                        param["requiredAt"] = update.requiredAt.time

                                        currentActivity?.runOnUiThread {
                                            channel.invokeMethod("onReportAvailableUpdate", param)
                                            generateLog(
                                                    "onReportAvailableUpdate",
                                                    "onReportAvailableUpdate ${update.version}"
                                            )
                                        }
                                    }

                                    override fun onStartInstallingUpdate(
                                            update: ReaderSoftwareUpdate,
                                            cancelable: Cancelable?
                                    ) {
                                        super.onStartInstallingUpdate(update, cancelable)
                                        cancelableInstallation = cancelable
                                        currentActivity?.runOnUiThread {
                                            channel.invokeMethod("onStartInstallingUpdate", update.version)
                                            generateLog(
                                                    "onStartInstallingUpdate",
                                                    "onStartInstallingUpdate ${update.version}"
                                            )
                                        }
                                    }

                                    override fun onReportReaderSoftwareUpdateProgress(progress: Float) {
                                        super.onReportReaderSoftwareUpdateProgress(progress)
                                        currentActivity?.runOnUiThread {
                                            channel.invokeMethod("onReportReaderSoftwareUpdateProgress", progress)
                                            generateLog(
                                                    "onReportReaderSoftwareUpdateProgress",
                                                    "onReportReaderSoftwareUpdateProgress $progress"
                                            )
                                        }
                                    }

                                    override fun onFinishInstallingUpdate(
                                            update: ReaderSoftwareUpdate?,
                                            e: TerminalException?
                                    ) {
                                        super.onFinishInstallingUpdate(update, e)
                                        if (update != null) {
                                            var result = "Install Success"
                                            if (e != null) {
                                                result = e.errorMessage
                                            }

                                            val param: HashMap<String, Any> = HashMap()
                                            param["versionString"] = update.version
                                            param["success"] = (e == null)
                                            param["result"] = result

                                            currentActivity?.runOnUiThread {
                                                channel.invokeMethod("onFinishInstallingUpdate", param)
                                                generateLog(
                                                        "onFinishInstallingUpdate",
                                                        "onFinishInstallingUpdate $result"
                                                )
                                            }
                                        }
                                    }

                                    override fun onRequestReaderDisplayMessage(message: ReaderDisplayMessage) {
                                        super.onRequestReaderDisplayMessage(message)
                                        currentActivity?.runOnUiThread {
                                            channel.invokeMethod("onRequestReaderDisplayMessage", handlerReaderMessage(message))
                                            generateLog(
                                                    "onRequestReaderDisplayMessage",
                                                    "onRequestReaderDisplayMessage $message"
                                            )
                                        }
                                    }
                                    override fun onReportReaderEvent(event: ReaderEvent) {
                                        super.onReportReaderEvent(event)
                                        currentActivity?.runOnUiThread {
                                            generateLog(
                                                    "onReportReaderEvent",
                                                    "readerEvent ${event}"
                                            )
                                        }
                                    }
                                },
                                object : ReaderCallback {
                                    override fun onFailure(e: TerminalException) {
                                        result.error(
                                                "stripeTerminal#unableToConnect",
                                                e.errorMessage,
                                                e.stackTraceToString()
                                        )
                                    }

                                    override fun onSuccess(reader: Reader) {
                                        result.success(true)
                                    }

                                })
                    }
                    ConnectionStatus.CONNECTING -> {
                        result.error(
                                "stripeTerminal#deviceConnecting",
                                "A new connection is being established with a device thus you cannot request a new connection at the moment.",
                                null
                        )
                    }
                    ConnectionStatus.CONNECTED -> {
                        result.error(
                                "stripeTerminal#deviceAlreadyConnected",
                                "A device with serial number ${Terminal.getInstance().connectedReader!!.serialNumber} is already connected",
                                null
                        )
                    }
                }
            }
//            "readReusableCardDetail" -> {
//                generateLog("readReusableCardDetail", "Started reading payment method")
//
//                if (Terminal.getInstance().connectedReader == null) {
//                    result.error(
//                        "stripeTerminal#deviceNotConnected",
//                        "You must connect to a device before you can use it.",
//                        null
//                    )
//                } else {
//                    val params = ReadReusableCardParameters.Builder().build()
//                    Terminal.getInstance().readReusableCard(params, object : PaymentMethodCallback {
//                        override fun onFailure(e: TerminalException) {
//                            result.error(
//                                "stripeTerminal#unableToReadCardDetail",
//                                "Device was not able to read payment method details because ${e.errorMessage}",
//                                e.stackTraceToString()
//                            )
//                        }
//
//                        override fun onSuccess(paymentMethod: PaymentMethod) {
//                            result.success(paymentMethod.rawJson())
//                        }
//
//                    })
//                }
//            }
            "collectPaymentMethod" -> {
                generateLog("check last payment", "Started check last payment ${cancelablePayment?.isCompleted}")
                generateLog("collectPaymentMethod", "Started reading payment method")
                currentActivity?.runOnUiThread {
                    channel.invokeMethod("onRequestReaderDisplayMessage", -1)
                }
                callbackPaymentIntentStatus(null, CustomPaymentStatus.NOT_PAYMENT, null)
                if (Terminal.getInstance().connectedReader == null) {
                    result.error(
                        "stripeTerminal#deviceNotConnected",
                        "You must connect to a device before you can use it.",
                        null
                    )
                    return
                }

                val arguments = call.arguments as HashMap<*, *>
                val paymentIntentClientSecret =
                    arguments["paymentIntentClientSecret"] as String?
                if (paymentIntentClientSecret == null) {
                    result.error(
                        "stripeTerminal#invalidPaymentIntentClientSecret",
                        "The payment intent client_secret seems to be invalid or missing.",
                        null
                    )
                    return
                }

                val collectConfiguration =
                    arguments["collectConfiguration"] as HashMap<*, *>
                val collectConfig = CollectConfiguration.Builder().skipTipping(collectConfiguration["skipTipping"] as Boolean).build()
                generateLog(
                    "【retrievePaymentIntent】",
                    "=======【waiting retrievePaymentIntent】======"
                )

                // 检索支付
                callbackPaymentIntentStatus(
                    null,
                    CustomPaymentStatus.START_RETRIEVE_PAYMENT_INTENT,
                    null
                )
                Terminal.getInstance()
                    .retrievePaymentIntent(
                        paymentIntentClientSecret,
                        handleGetPaymentIntent(call, result, collectConfig)
                    )
            }
            "createPaymentMethod" -> {
                generateLog("check last payment", "Started check last payment ${cancelablePayment?.isCompleted} before create payment")
                generateLog("createPaymentMethod", "Started creating payment method")
                // 重置缓存的 paymentIntent
                currentPaymentIntent = null
                // 重置读卡器显示信息
                currentActivity?.runOnUiThread {
                    channel.invokeMethod("onRequestReaderDisplayMessage", -1)
                }
                // 重置自定义的支付状态
                callbackPaymentIntentStatus(null, CustomPaymentStatus.NOT_PAYMENT, null)

                val arguments = call.arguments as HashMap<*, *>
                val amount = arguments["paymentAmount"] as Int
                val orderId = arguments["orderId"] as String
                val orderSn = arguments["orderSn"] as String
                val storeName = arguments["storeName"] as String
                val autoCapture = arguments["autoCapture"] as Boolean
                var captureMethod = CaptureMethod.Automatic
                if (!autoCapture) {
                    captureMethod = CaptureMethod.Manual
                }
                // 创建支付
                // 元数据，用于透传订单号
                val metaData = HashMap<String, String>()
                metaData["orderId"] = orderId
                metaData["orderSn"] = orderSn
                // 允许的支付类型，目前仅允许用卡支付
                val allowedPaymentMethodTypes = listOf(PaymentMethodType.CARD_PRESENT)
                // 生产创建支付的参数
                val params =
                    PaymentIntentParameters.Builder(allowedPaymentMethodTypes = allowedPaymentMethodTypes)
                        .setAmount(amount.toLong())
                        .setCurrency("usd")
                        .setCaptureMethod(captureMethod)
                        .setDescription(storeName)
                        .setMetadata(metaData)
                        .setSetupFutureUsage("off_session")
                        .build()
                callbackPaymentIntentStatus(
                    null,
                    CustomPaymentStatus.START_CREATE_PAYMENT_INTENT,
                    null
                )
                Terminal.getInstance()
                    .createPaymentIntent(params, object : PaymentIntentCallback {
                        override fun onSuccess(paymentIntent: PaymentIntent) {
                            currentPaymentIntent = paymentIntent
                            result.success(paymentIntent.rawJson())
                            callbackPaymentIntentStatus(
                                currentPaymentIntent,
                                CustomPaymentStatus.CREATE_PAYMENT_INTENT_SUCCESS,
                                null
                            )
                            currentActivity?.runOnUiThread {
                                generateLog(
                                    "【createPayment】",
                                    "=======【done createPayment success】======"
                                )
                                generateLog(
                                    "createPayment",
                                    Gson().toJson(paymentIntent.rawJson())
                                )
                            }
                        }

                        override fun onFailure(e: TerminalException) {
                            currentPaymentIntent = null
                            result.error(
                                "stripeTerminal#unableToCreatePayment",
                                "Stripe reader was not able to create the payment intent. ${e.errorMessage}",
                                e.stackTraceToString()
                            )
                            callbackPaymentIntentStatus(null, CustomPaymentStatus.CREATE_PAYMENT_INTENT_FAIL, e)
                            currentActivity?.runOnUiThread {
                                generateLog(
                                    "【createPayment】",
                                    "=======【done createPayment fail】======"
                                )
                            }
                        }
                    })
            }
            "collectAfterCreatePayment" -> {
                if (currentPaymentIntent == null) {
                    result.error(
                        "stripeTerminal#unableToCollectPaymentMethod",
                        "Stripe reader was not able to collect the payment method because payment intent is null.",
                        null
                    )
                    return
                }

                callbackPaymentIntentStatus(currentPaymentIntent, CustomPaymentStatus.START_COLLECT_PAYMENT_METHOD, null)

                val arguments = call.arguments as HashMap<*, *>
                val collectConfiguration =
                    arguments["collectConfiguration"] as HashMap<*, *>
                val collectConfig = CollectConfiguration.Builder().skipTipping(collectConfiguration["skipTipping"] as Boolean).build()
                currentOrderId = arguments["orderId"] as String
                val orderId =  arguments["orderId"] as String
                cancelablePayment = Terminal.getInstance().collectPaymentMethod(
                    currentPaymentIntent!!,
                    object : PaymentIntentCallback {
                        override fun onSuccess(paymentIntent: PaymentIntent) {
                            if (paymentIntent.metadata != null && (paymentIntent.metadata!!["orderId"] as String) != currentOrderId) {
                                return
                            }
                            callbackPaymentIntentStatus(paymentIntent, CustomPaymentStatus.START_PROCESS_PAYMENT, null)
                            currentActivity?.runOnUiThread {
                                generateLog(
                                    "【collectPaymentMethod】",
                                    "=======【done collectPaymentMethod success】======"
                                )
                                generateLog(
                                    "collectPaymentMethod",
                                    Gson().toJson(paymentIntent.rawJson())
                                )
                                generateLog(
                                    "【processPayment】",
                                    "=======【waiting processPayment】======"
                                )
                            }
                            Terminal.getInstance()
                                .confirmPaymentIntent(
                                    paymentIntent,
                                    handleCollectPaymentIntent(call, result))
                        }

                        override fun onFailure(e: TerminalException) {
                            if (orderId != currentOrderId) {
                                return
                            }
                            callbackPaymentIntentStatus(null, CustomPaymentStatus.COLLECT_PAYMENT_METHOD_FAIL, e)
                            currentActivity?.runOnUiThread {
                                generateLog(
                                    "【collectPaymentMethod】",
                                    "=======【done collectPaymentMethod fail】======"
                                )
                            }
                            result.error(
                                "stripeTerminal#unableToCollectPaymentMethod",
                                "Stripe reader was not able to collect the payment method for the provided payment intent. ${e.errorMessage}",
                                e.stackTraceToString()
                            )
                        }
                    },
                    collectConfig,
                )
            }
            "cancelPayment" -> {
                if (cancelablePayment == null) {
                    result.error(
                        "stripeTerminal#unabelToCancelPayment",
                        "There is no processing payment.",
                        null
                    )
                } else {
                    cancelablePayment?.cancel(object : Callback {
                        override fun onFailure(e: TerminalException) {
                            result.error(
                                "stripeTerminal#unabelToCancelPayment",
                                "Unable to cancel action because ${e.errorMessage}",
                                e.stackTraceToString()
                            )
                        }

                        override fun onSuccess() {
                            result.success(true)
                        }
                    })
                    cancelablePayment = null
                }
            }
            "disconnectFromReader" -> {
                if (Terminal.getInstance().connectedReader != null) {
                    Terminal.getInstance().disconnectReader(object : Callback {
                        override fun onFailure(e: TerminalException) {
                            result.error(
                                "stripeTerminal#unableToDisconnect",
                                "Unable to disconnect from a reader because ${e.errorMessage}",
                                e.stackTraceToString()
                            )
                        }

                        override fun onSuccess() {
                            currentActivity?.runOnUiThread {
                                generateLog("stripeTerminal#disconnectFromReader", "callback onSuccess")
                                result.success(true)
                            }
                        }
                    })
                } else {
                    result.error(
                        "stripeTerminal#unableToDisconnect",
                        "No reader connected to disconnect from.",
                        null
                    )
                }
            }
            "updateCurrentReader" -> {
                if (Terminal.getInstance().connectedReader != null) {
                    if (Terminal.getInstance().connectedReader?.availableUpdate == null) {
                        result.error(
                            "stripeTerminal#unableToUpdateReader",
                            "Reader does not need update",
                            null
                        )
                    }
                    Terminal.getInstance().installAvailableUpdate()
                    result.success(true)
                } else {
                    result.error(
                        "stripeTerminal#unableToUpdateReader",
                        "No reader connected",
                        null
                    )
                }
            }
            else -> result.notImplemented()
        }
    }

    private fun handleGetPaymentIntent(@NonNull call: MethodCall, @NonNull result: Result, @NonNull collectConfig: CollectConfiguration): PaymentIntentCallback {
        return object : PaymentIntentCallback {
            override fun onFailure(e: TerminalException) {
                callbackPaymentIntentStatus(null, CustomPaymentStatus.RETRIEVE_PAYMENT_INTENT_FAIL, e)
                currentActivity?.runOnUiThread {
                    generateLog(
                        "【retrievePaymentIntent】",
                        "=======【done retrievePaymentIntent fail】======"
                    )
                }
                result.error(
                    "stripeTerminal#unableToRetrivePaymentIntent",
                    "Stripe was not able to fetch the payment intent with the provided client secret. ${e.errorMessage}",
                    e.stackTraceToString()
                )
            }

            override fun onSuccess(paymentIntent: PaymentIntent) {
                callbackPaymentIntentStatus(paymentIntent, CustomPaymentStatus.START_COLLECT_PAYMENT_METHOD, null)
                currentActivity?.runOnUiThread {
                    generateLog(
                        "【collectPaymentMethod】",
                        "=======【done retrievePaymentIntent success】======"
                    )
                    generateLog(
                        "【collectPaymentMethod】",
                        "=======【waiting collectPaymentMethod】======"
                    )
                }
                cancelablePayment = Terminal.getInstance().collectPaymentMethod(
                    paymentIntent,
                    object : PaymentIntentCallback {
                        override fun onSuccess(paymentIntent: PaymentIntent) {
                            callbackPaymentIntentStatus(paymentIntent, CustomPaymentStatus.START_PROCESS_PAYMENT, null)
                            currentActivity?.runOnUiThread {
                                generateLog(
                                    "【collectPaymentMethod】",
                                    "=======【done collectPaymentMethod success】======"
                                )
                                generateLog(
                                    "collectPaymentMethod",
                                    Gson().toJson(paymentIntent.rawJson())
                                )
                                generateLog(
                                    "【processPayment】",
                                    "=======【waiting processPayment】======"
                                )
                            }
                            Terminal.getInstance()
                                .confirmPaymentIntent(
                                    paymentIntent,
                                    handleCollectPaymentIntent(call, result))
                        }

                        override fun onFailure(e: TerminalException) {
                            callbackPaymentIntentStatus(null, CustomPaymentStatus.COLLECT_PAYMENT_METHOD_FAIL, e)
                            currentActivity?.runOnUiThread {
                                generateLog(
                                    "【collectPaymentMethod】",
                                    "=======【done collectPaymentMethod fail】======"
                                )
                            }
                            result.error(
                                "stripeTerminal#unableToCollectPaymentMethod",
                                "Stripe reader was not able to collect the payment method for the provided payment intent. ${e.errorMessage}",
                                e.stackTraceToString()
                            )
                        }
                    },
                    collectConfig,
                )
            }
        }
    }

    private fun handleCollectPaymentIntent(@NonNull call: MethodCall, @NonNull result: Result): PaymentIntentCallback {
        return object : PaymentIntentCallback {
            override fun onSuccess(paymentIntent: PaymentIntent) {
                callbackPaymentIntentStatus(paymentIntent, CustomPaymentStatus.PROCESS_PAYMENT_SUCCESS, null)
                currentActivity?.runOnUiThread {
                    generateLog(
                        "【processPayment】",
                        "=======【done processPayment success】======"
                    )
                    generateLog(
                        "processPayment",
                        Gson().toJson(paymentIntent.rawJson())
                    )
                }
                result.success(paymentIntent.rawJson())
            }

            override fun onFailure(e: TerminalException) {
                callbackPaymentIntentStatus(null, CustomPaymentStatus.PROCESS_PAYMENT_FAIL, e)
                currentActivity?.runOnUiThread {
                    generateLog(
                        "【processPayment】",
                        "=======【done processPayment fail】======"
                    )
                }
                result.error(
                    "stripeTerminal#unableToProcessPayment",
                    "Stripe reader was not able to process the payment for the provided payment intent. ${e.errorMessage}",
                    e.stackTraceToString()
                )
            }
        }
    }

    private fun callbackPaymentIntentStatus(paymentIntent: PaymentIntent?, paymentStatus: CustomPaymentStatus, exception: TerminalException?) {
        val param: HashMap<String, Any> = HashMap()
        param["paymentStatus"] = handleCustomPaymentStatus(paymentStatus)
        if (exception != null) {
            val exceptionMap: HashMap<String, String> = HashMap()
            exceptionMap["errorCode"] = exception.errorCode.toString()
            exceptionMap["errorMessage"] = exception.errorMessage
            param["exception"] = JSONObject(exceptionMap as Map<*, *>?).toString()
        }
        if (paymentIntent != null) {
            param["paymentIntent"] = paymentIntent.rawJson()
        }

        try {
            currentActivity?.runOnUiThread {
                println("========>>>>>>$paymentStatus");
                channel.invokeMethod("callbackPaymentIntentStatus", param)
            }
        } catch (e: RuntimeException) {
            println("========>>>>>>${e.message}")
        }
        return
    }

    var result: Result? = null

    private fun _isLocServiceEnable():Boolean{
        val mLocationManager: LocationManager?= currentActivity!!.applicationContext.getSystemService(LOCATION_SERVICE) as LocationManager?
        val gps:Boolean?=mLocationManager?.isProviderEnabled(LocationManager.GPS_PROVIDER)
        val network:Boolean?= mLocationManager?.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
        if(gps!! || network!!){
            return true
        }
        return false
    }

    private fun _isPermissionAllowed(result: Result): Boolean {
        val permissionStatus = permissions.map {
            ContextCompat.checkSelfPermission(currentActivity!!, it)
        }

        if (!permissionStatus.contains(PackageManager.PERMISSION_DENIED)) {
            result.success(true)
            return true
        }

        val cannotAskPermissions = permissions.map {
            ActivityCompat.shouldShowRequestPermissionRationale(currentActivity!!, it)
        }

        if (cannotAskPermissions.contains(true)) {
            result.error(
                "stripeTerminal#permissionDeclinedPermanenty",
                "You have declined the necessary permission, please allow from settings to continue.",
                null
            )
            return false
        }

        this.result = result

        ActivityCompat.requestPermissions(currentActivity!!, permissions, REQUEST_CODE_LOCATION)

        return false
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ): Boolean {
        if (requestCode != REQUEST_CODE_LOCATION) {
            return false
        }
        val permissionStatus = permissions.map {
            ContextCompat.checkSelfPermission(currentActivity!!, it)
        }
        if ((!permissionStatus.contains(PackageManager.PERMISSION_DENIED))) {
            _startStripe()
        } else {
            result?.error(
                "stripeTerminal#insuffecientPermission",
                "You have not provided enough permission for the scanner to work",
                null
            )
        }
        return true
    }


    override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
        channel.setMethodCallHandler(null)
        if (Terminal.isInitialized()) {
            if (Terminal.getInstance().connectedReader != null) {
                Terminal.getInstance().disconnectReader(object : Callback {
                    override fun onFailure(e: TerminalException) {
                    }

                    override fun onSuccess() {
                    }
                })
            }
            cancelableDiscover?.cancel(
                    object : Callback {
                        override fun onFailure(e: TerminalException) {
                        }

                        override fun onSuccess() {
                        }
                    }
            )
            cancelableDiscover = null
        }
    }

    override fun onDetachedFromActivity() {
        currentActivity = null
    }

    override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
        currentActivity = binding.activity
        tokenProvider = StripeTokenProvider(currentActivity!!, channel)
        binding.addRequestPermissionsResultListener(this)
    }

    override fun onAttachedToActivity(binding: ActivityPluginBinding) {
        currentActivity = binding.activity
        TerminalApplicationDelegate.onCreate(currentActivity!!.application)
        tokenProvider = StripeTokenProvider(currentActivity!!, channel)
        binding.addRequestPermissionsResultListener(this)
    }

    override fun onDetachedFromActivityForConfigChanges() {
        currentActivity = null
    }


    /*
     These functions are stub functions that are not relevent to the plugin but needs to be defined in order to get the few necessary callbacks
    */

    override fun onCreate(savedInstanceState: Bundle?) {
        TODO("Not yet implemented")
    }

    override fun onNewIntent(intent: Intent?) {
        TODO("Not yet implemented")
    }

    override fun onPause() {
        TODO("Not yet implemented")
    }

    override fun onStart() {
        TODO("Not yet implemented")
    }

    override fun onResume() {
        TODO("Not yet implemented")
    }

    override fun onPostResume() {
        TODO("Not yet implemented")
    }

    override fun onDestroy() {
        TODO("Not yet implemented")
    }

    override fun onStop() {
        TODO("Not yet implemented")
    }

    override fun onBackPressed(): Boolean {
        TODO("Not yet implemented")
    }

    override fun onUserLeaveHint() {
        TODO("Not yet implemented")
    }

    override fun onWindowFocusChanged(hasFocus: Boolean) {
        TODO("Not yet implemented")
    }

    override fun onConfigurationChanged(p0: Configuration) {
        TODO("Not yet implemented")
    }

    override fun onLowMemory() {
        TODO("Not yet implemented")
    }

    override fun onTrimMemory(p0: Int) {
//        @Deprecated("V3.2.0 TerminalApplicationDelegate.onTrimMemory() is removed. It is automatically managed by the SDK.")
//        TerminalApplicationDelegate.onTrimMemory(currentActivity!!.application, p0)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean {
        TODO("Not yet implemented")
    }


}


fun Reader.rawJson(): HashMap<String, Any?> {
    val json = HashMap<String, Any?>()
    json["locationStatus"] = locationStatus.ordinal
    json["batteryStatus"] = handleBatteryLevel(batteryLevel)
    json["deviceType"] = handleDeviceType(deviceType)
    json["originalJSON"] = rawReaderData
    json["simulated"] = isSimulated
    json["label"] = label
    json["availableUpdate"] = availableUpdate?.hasFirmwareUpdate ?: false
    json["locationId"] = location?.id
    json["serialNumber"] = serialNumber
    return json
}

fun PaymentIntent.rawJson(): HashMap<String, Any?> {
    val json = HashMap<String, Any?>()
    json["id"] = id
    json["amount"] = amount
    json["amount_capturable"] = amountCapturable
    json["amount_received"] = amountReceived
    json["application"] = application
    json["application_fee_amount"] = applicationFeeAmount
    json["capture_method"] = captureMethod
    json["cancellation_reason"] = cancellationReason
    json["canceled_at"] = canceledAt
    json["client_secret"] = clientSecret
    json["confirmation_method"] = confirmationMethod
    json["created"] = created
    json["currency"] = currency
    json["customer"] = customer
    json["description"] = description
    json["invoice"] = invoice
    json["livemode"] = livemode
    json["metadata"] = metadata
    json["on_behalf_of"] = onBehalfOf
    json["payment_method_id"] = paymentMethodId
    json["status"] = status?.name?.lowercase()
    json["review"] = review
    json["receipt_email"] = receiptEmail
    json["transfer_group"] = transferGroup
    json["setup_future_usage"] = setupFutureUsage

    return json
}

fun handleConnectionStatus(connectionStatus: ConnectionStatus): Int {
    return when (connectionStatus) {
        ConnectionStatus.NOT_CONNECTED -> 0
        ConnectionStatus.CONNECTING -> 2
        ConnectionStatus.CONNECTED -> 1
        else -> 0
    }
}

fun handlePaymentStatus(paymentStatus: PaymentStatus): Int {
    return when (paymentStatus) {
        PaymentStatus.NOT_READY -> 0
        PaymentStatus.READY -> 1
        PaymentStatus.WAITING_FOR_INPUT -> 2
        PaymentStatus.PROCESSING -> 3
        else -> 0
    }
}

fun handleBatteryLevel(batteryValue: Float?): Int {
    return when {
        batteryValue == null -> 0
        batteryValue <= .05 -> 1
        batteryValue <= .20 -> 2
        batteryValue > .20 -> 3
        else -> 0
    }
}

fun handleDeviceType(deviceType: DeviceType): Int {
    return when (deviceType) {
        DeviceType.CHIPPER_1X -> 5
        DeviceType.CHIPPER_2X -> 0
        DeviceType.STRIPE_M2 -> 3
        DeviceType.COTS_DEVICE -> 7
        DeviceType.VERIFONE_P400 -> 1
        DeviceType.WISECUBE -> 6
        DeviceType.WISEPAD_3 -> 7
        DeviceType.WISEPOS_E -> 4
        DeviceType.ETNA -> 7
        DeviceType.UNKNOWN -> 7
        else -> 7
    }

}

fun handlerReaderMessage(message: ReaderDisplayMessage) : Int {
    return when (message) {
        ReaderDisplayMessage.CHECK_MOBILE_DEVICE -> 0
        ReaderDisplayMessage.RETRY_CARD -> 1
        ReaderDisplayMessage.INSERT_CARD -> 2
        ReaderDisplayMessage.INSERT_OR_SWIPE_CARD -> 3
        ReaderDisplayMessage.SWIPE_CARD -> 4
        ReaderDisplayMessage.REMOVE_CARD -> 5
        ReaderDisplayMessage.MULTIPLE_CONTACTLESS_CARDS_DETECTED -> 6
        ReaderDisplayMessage.TRY_ANOTHER_READ_METHOD -> 7
        ReaderDisplayMessage.TRY_ANOTHER_CARD -> 8
        ReaderDisplayMessage.CARD_REMOVED_TOO_EARLY -> 9
    }
}

fun PaymentMethod.rawJson(): HashMap<String, Any?> {

    val json = HashMap<String, Any?>()
    json["id"] = id
    json["metadata"] = metadata
    json["billing_details"] = HashMap<Any, Any?>()
    json["object"] = "payment_method"
    json["created"] = System.currentTimeMillis() / 1000
    json["livemode"] = livemode
    json["type"] = "card"  // Not sure why there is no type object, probably M2 can only scan cards
    json["card"] = cardDetails?.rawJson()
    json["customer"] = customer
    return json

}

fun CardDetails.rawJson(): HashMap<String, Any?> {
    val json = HashMap<String, Any?>()

    json["brand"] = brand
    json["country"] = country
    json["exp_month"] = expMonth
    json["exp_year"] = expYear
    json["funding"] = funding
    json["last4"] = last4
    return json
}

enum class CustomPaymentStatus {
    NOT_PAYMENT,
    START_RETRIEVE_PAYMENT_INTENT,
    RETRIEVE_PAYMENT_INTENT_FAIL,
    START_COLLECT_PAYMENT_METHOD,
    COLLECT_PAYMENT_METHOD_FAIL,
    START_PROCESS_PAYMENT,
    PROCESS_PAYMENT_FAIL,
    PROCESS_PAYMENT_SUCCESS,
    START_CREATE_PAYMENT_INTENT,
    CREATE_PAYMENT_INTENT_FAIL,
    CREATE_PAYMENT_INTENT_SUCCESS,
}

fun handleCustomPaymentStatus(paymentStatus: CustomPaymentStatus): Int {
    return when (paymentStatus) {
        CustomPaymentStatus.NOT_PAYMENT -> 0
        CustomPaymentStatus.START_RETRIEVE_PAYMENT_INTENT -> 1
        CustomPaymentStatus.RETRIEVE_PAYMENT_INTENT_FAIL -> 2
        CustomPaymentStatus.START_COLLECT_PAYMENT_METHOD -> 3
        CustomPaymentStatus.COLLECT_PAYMENT_METHOD_FAIL -> 4
        CustomPaymentStatus.START_PROCESS_PAYMENT -> 5
        CustomPaymentStatus.PROCESS_PAYMENT_FAIL -> 6
        CustomPaymentStatus.PROCESS_PAYMENT_SUCCESS -> 7
        CustomPaymentStatus.START_CREATE_PAYMENT_INTENT -> 8
        CustomPaymentStatus.CREATE_PAYMENT_INTENT_FAIL -> 9
        CustomPaymentStatus.CREATE_PAYMENT_INTENT_SUCCESS -> 10
    }
}